from django.contrib.auth.models import User

import current_user_middleware as threadlocals
from django.contrib.contenttypes.models import ContentType
from django.contrib.admin.models import ADDITION,CHANGE,DELETION, LogEntry
from django.db import models
from django.db.models import signals
from django import forms
from django.db.models.base import ModelBase
import datetime
from django.core import serializers
from django.utils.translation import ugettext_lazy as _

from xadmin.models import UpdatesHistory
ACTION_CHOICE = (
                 (ADDITION,"ADDITION"),
                 (CHANGE, "CHANGE"),
                 (DELETION, "DELETION")
                 )


def boolean_field_to_python(value):
    """
    >>> boolean_field_to_python(True)
    True
    >>> boolean_field_to_python("t")
    True
    >>> boolean_field_to_python(1)
    True
    >>> try: 
    ...     boolean_field_to_python(6)
    ... except forms.ValidationError, e: 
    ...     print e    
    [u'This value must be either True or False.']
    
    """
    
    if value in ('t', 'True', '1', 1): return True
    if value in ('f', 'False', '0', 0): return False
    if value in (True, False): return value
    raise forms.ValidationError("This value must be either True or False.")

def prepare_fields(instance):
#    print 66666, 
#    print instance
#    print type(instance)
#    print instance._history['fields']
    output = {}
    class_fields = instance.__class__._meta.fields
    instance._history['old_values'] = {}
    all = dict([(f.name, f) for f in class_fields])
    for field_name in instance._history['fields']:
        modelfield = all.get(field_name,False)
        value = getattr(instance, modelfield.attname)
        print 1111, field_name, value
        value = modelfield.to_python(value)     
        if value is None: value = ''
        output[field_name] = unicode(value)
#    
#    print "=" * 30
#    print output
#    print "=" * 30
#    return output

def add_signals(cls):
    def post_delete(instance, **_kwargs):
        if instance._history['delete']:
            instance._create_history_log_entry(DELETION)

    def pre_save(instance, **_kwargs):
        if instance._history.get('fields', []):
            if instance.pk is None:
                instance._history['old_values'] = {}
                for field_name in instance._history['fields']:
                    instance._history['old_values'][field_name] = ''
            else:
                try:
                    db_instance = instance.__class__.objects.get(pk=instance.pk)
                except instance.__class__.DoesNotExist:
                    db_instance = instance
                instance._history['old_values'] = prepare_fields(db_instance)

        
    def post_save(instance, **_kwargs):
        isNew =  bool(_kwargs['created'])
        try:
           if instance._history['add'] and isNew:
               data = serializers.serialize("json", [instance] )
           elif instance._history['upd']:
               pre_fields = instance._history['old_values']
               post_fields = prepare_fields(instance)
               h = []
               for name, after in post_fields.iteritems():
#                   try:
#                       t = type(getattr(instance, name))
#                   except:
#                       pass
#                   
#                   if t == bool:
#                       before = boolean_field_to_python(pre_fields[name]) 
#                       after = boolean_field_to_python( after )
#                   else:
                    before = pre_fields[name] 
                                           
                    if before != after:                    
                       h.append("%s => '%s':'%s'" % (name, before,after ) )
                       
               data = "\n".join(h)
           
           if data:
               instance._create_history_log_entry( ADDITION if isNew else CHANGE, data )
        except instance.DoesNotExist:
            pass
         
    signals.pre_save.connect(pre_save, sender=cls, weak=False)
    signals.post_save.connect(post_save, sender=cls, weak=False)
    signals.post_delete.connect(post_delete, sender=cls, weak=False)


class HistoryModelBase(ModelBase):
            
    def __new__(cls, name, bases, attrs):
        Model = ModelBase.__new__(cls, name, bases, attrs)
        _history = getattr(Model, 'History', None)
        
        history = {'delete': True, 'upd':True,'add':True, 'fields': [] }        
        meta = getattr(Model, '_meta', None)
        history['fields'] =  [f.name for f in meta.fields if f.primary_key==False]

        if _history:
            history.update( _history.__dict__ )

        Model._history = history        
        from django.conf import settings
        if not getattr(settings, 'LOADING_FIXTURES', False):  
            add_signals(Model)
            pass        
        return Model
    
class HistoryModel(models.Model):
    __metaclass__ = HistoryModelBase
    __contentType = None
    class Meta:
        abstract = True
    
    def __init__(self, *args, **kwargs):
        super(HistoryModel, self).__init__(*args, **kwargs)
        from django.conf import settings        
#        if not "kommon.models.history_model_middleware.HistoryModelMiddleware" in settings.MIDDLEWARE_CLASSES:
#            raise Exception("HistoryModelMiddleware must be present in MIDDLEWARE_CLASSES")
        
        self.history_disabled = False
        
    def _create_history_log_entry(self, action, changes=""):         
        user = threadlocals.get_current_user()   
        
        history = UpdatesHistory(action_flag = action, user=user, 
                                 object_id = self.pk,changes=changes,
                                 content_type = self.get_content_type() )
        try:
            history.object_repr = repr(self)
        except Exception:
            history.object_repr = "(unknown)"
        
        history.save()
        
    def get_content_type(self):
        if not self.__contentType:
            self.__contentType = ContentType.objects.get_for_model(self)     
        return self.__contentType
        
    def get_history(self):
        #from crm.models import UpdatesHistory
        #content_type = ContentType.objects.get_for_model(self)
        return UpdatesHistory.objects.filter(object_id=self.pk, content_type=self.get_content_type() ).order_by("action_time", "pk")

    def get_last_history_entry(self):
        #from crm.models import UpdatesHistory
        #content_type = ContentType.objects.get_for_model(self)
        try:
            return UpdatesHistory.objects.filter(object_id=self.pk, content_type=self.get_content_type()).latest()
        except UpdatesHistory.DoesNotExist:
            return None
        
        #return UpdatesHistory.objects.filter(object_id=self.pk, content_type=self.get_content_type() ).order_by("-action_time", "-pk")[0]        
        #return self.get_history()[0]
        
    def last_edited_at(self):
        #history = list(self.get_history()[:1])
        history = self.get_last_history_entry()
        if not history:
            return datetime.datetime(2000, 1, 1, 0, 0, 0)
        else:
            return history.action_time
        
    def last_edited_by(self):
        #history = list(self.get_history()[:1])
        history = self.get_last_history_entry()
        if not history:
            return None
        else:
            return history.user    
        
